import dayjs from 'dayjs';
import logger from './logger';
import fs from '@ohos.file.fs';
import buffer from '@ohos.buffer';
import window from '@ohos.window';
import request from '@ohos.request';
import cryptoJS from '@ohos/crypto-js';
import Match from '../model/common/Match';
import dict, { BUNDLE_NAME } from './dict';
import settingHelper from './settingHelper';
import promptAction from '@ohos.promptAction';
import common from '@ohos.app.ability.common';
import connection from '@ohos.net.connection';
import memoryImage from '../model/other/memoryImage';
import notification from '@ohos.notificationManager';
import relationalStore from '@ohos.data.relationalStore';

class utils {
  changeOrientation(context: common.Context, isLandscape: boolean) {
    try {
      window.getLastWindow(context).then((lastWindow) => {
        lastWindow.setPreferredOrientation(isLandscape ? window.Orientation.LANDSCAPE : window.Orientation.PORTRAIT);
      });
    } catch (e) {
      logger.error(e);
    }
  }

  async createRdbStore(context: common.Context) {
    try {
      if (this.isEmpty(globalThis.rdbStore)) {
        await relationalStore.getRdbStore(context, dict.STORE_CONFIG).then((rdbStore: relationalStore.RdbStore) => {
          if (!this.isEmpty(rdbStore)) {
            rdbStore.executeSql(dict.CREATE_TABLE_FORM);
            globalThis.rdbStore = rdbStore;
          }
        });
      }
    } catch (e) {
      logger.error(e);
    }
    return globalThis.rdbStore;
  }

  parseQueryString(queryString: string): object {
    let params = {};
    try {
      let keyValuePairs = queryString.split('&');
      for (let i = 0; i < keyValuePairs.length; i++) {
        let pair = keyValuePairs[i].split('=');
        let key = decodeURIComponent(pair[0]);
        let value = decodeURIComponent(pair[1] || '');
        params[key] = value;
      }
    } catch (e) {
      logger.error(e);
    }
    return params;
  }

  isMobileNetwork(): Promise<boolean> {
    return new Promise((resolve) => {
      try {
        connection.getDefaultNet().then((res) => {
          connection.getNetCapabilities(res).then((handle) => {
            var result = handle.bearerTypes.includes(connection.NetBearType.BEARER_CELLULAR);
            resolve(result);
          });
        });
      } catch (e) {
        logger.error(e);
        resolve(false);
      }
    });
  }

  buildMemoryImage(context: common.Context, urls: Array<string>): Promise<Array<memoryImage>> {
    let arr: Array<memoryImage> = [];
    return new Promise((resolve) => {
      try {
        for (var url of urls) {
          this.download(context, 0, url).then((mi) => {
            arr.push(mi);
            if (arr.length == urls.length)
              resolve(arr);
          });
        }
      } catch (e) {
        logger.error(e);
        resolve(arr);
      }
    });
  }

  getRandomInt(randomNumber: number): number {
    let roundNumber: number = Math.round(Math.random() * dict.MULTIPLY_TEN);
    if (roundNumber === randomNumber)
      roundNumber = this.getRandomInt(randomNumber);
    return roundNumber;
  }

  async setSystemBarShowHide(context: common.Context, show: boolean) {
    try {
      let windowClass = await window.getLastWindow(context);
      if (!show)
        await windowClass.setWindowSystemBarEnable([]);
      else
        await windowClass.setWindowSystemBarEnable(["status", "navigation"]);
    } catch (e) {
      logger.error(e);
    }
  }

  formatNumber(num: number | string | undefined | null): string {
    if (Number.isNaN(num)) {
      return '';
    } else {
      const realNum = typeof num === 'string' ? Number.parseInt(num) : num
      if (realNum < 10000)
        return realNum.toString();
      else if (realNum < 100000000)
        return (realNum / 10000).toFixed(1) + '万';
      else
        return (realNum / 100000000).toFixed(1) + '亿';

    }
  }

  formatDateAsYMDHmCN(date: Date | number | undefined | null): string {
    if (this.isEmpty(date))
      return '';
    const hour = Number.parseInt(dayjs(date).format('HH'));
    const minute = Number.parseInt(dayjs(date).format('mm'));
    return dayjs(date).format('YYYY年MM月DD日') + ' ' + (hour < 10 ? '0' + hour : hour) + ':' + (minute < 10 ? '0' + minute : minute);
  }

  formatTimeDiff(date: Date | number | undefined | null): string {
    if (this.isEmpty(date))
      return '';
    const now = dayjs();
    const diff = now.diff(date, 'minute');
    if (diff < 60)
      return `${diff}分钟前`;
    else if (diff < 24 * 60)
      return `${Math.floor(diff / 60)}小时前`;
    return dayjs(date).format('MM月DD日');
  }

  setLayoutFullScreen(windowStage: window.WindowStage, statusBarColor: string, statusBarContentColor: string,
                      navigationBarColor: string, navigationBarContentColor: string) {
    try {
      let windowClass: window.Window = null;
      windowStage.getMainWindow((err, data) => {
        if (err.code) return;
        windowClass = data;
        let isLayoutFullScreen = false;
        windowClass.setWindowLayoutFullScreen(isLayoutFullScreen);
        let sysBarProps = {
          statusBarColor: statusBarColor,
          statusBarContentColor: statusBarContentColor,
          navigationBarColor: navigationBarColor,
          navigationBarContentColor: navigationBarContentColor
        };
        windowClass.setWindowSystemBarProperties(sysBarProps);
      });
    } catch (e) {
      logger.error(e);
    }
  }

  regexMatch(input: string, reg: RegExp): Match {
    let output;
    try {
      let ms = input.match(reg);
      let res = ms[1].toString();
      if (this.isEmpty(res))
        output = new Match(false, '');
      else
        output = new Match(true, res);
    } catch (e) {
      logger.error(e);
      output = new Match(false, '');
    }
    return output;
  }

  md5(str) {
    return cryptoJS.MD5(str).toString()
  }

  uuid() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
      var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
      return v.toString(16);
    });
  }

  getQuery(url: string) {
    var index = url.indexOf('?');
    if (index > 0)
      return url.substring(index);
    return '';
  }

  parse<T>(json: string): T {
    let result: T = JSON.parse(json) as T;
    return result;
  }

  toJson(obj: any): string {
    return JSON.stringify(obj);
  }

  isEmpty(obj: any): boolean {
    if (typeof obj == 'undefined' || obj == null || obj?.toString().trim() == '')
      return true;
    return false;
  }

  buvid(): string {
    var mac = [];
    for (let i = 0; i < 6; i++) {
      var min = Math.min(0, 0xff)
      var max = Math.max(0, 0xff)
      var num = parseInt((Math.random() * (min - max + 1) + max).toString()).toString(16)
      mac.push(num)
    }
    var md5 = this.md5(mac.join(':'));
    var md5Arr = md5.split('');
    return `XY${md5Arr[2]}${md5Arr[12]}${md5Arr[22]}${md5}`
  }

  showPopup(msg: string, duration?: number) {
    try {
      if (!this.isEmpty(msg)) {
        if (this.isEmpty(duration))
          duration = 2000;
        promptAction.showToast({
          message: msg ?? '',
          duration: duration,
        });
      }
    } catch (e) {
      logger.error(e);
    }
  }

  showNotify(title: string, content: string): number {
    try {
      if (!settingHelper.notifyEnable)
        return -1;
      var id = globalThis.notifyId;
      if (this.isEmpty(id))
        id = 1;
      else
        id++;
      let notificationRequest = {
        id: id,
        content: {
          contentType: notification.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
          normal: {
            title: title,
            text: content
          }
        }
      };
      notification.publish(notificationRequest);
      return id;
    }
    catch (e) {
      logger.error(e);
      return -1;
    }
  }

  setNotify(isOn: boolean) {
    try {
      notification.setNotificationEnable({
        bundle: BUNDLE_NAME
      }, isOn);
    } catch (e) {
      logger.error(e);
    }
  }

  updateNotify(notifyId: number, title: string, content: string): number {
    try {
      if (notifyId != -1 && !settingHelper.notifyEnable) {
        let notificationRequest = {
          id: notifyId,
          content: {
            contentType: notification.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
            normal: {
              title: title,
              text: content
            }
          }
        };
        notification.publish(notificationRequest);
      }
    } catch (e) {
      logger.error(e);
    }
    return notifyId;
  }

  stringForTime(timeMs: any): string {
    try {
      let totalSeconds = (timeMs / 1000);
      let seconds = totalSeconds % 60;
      let minutes = (totalSeconds / 60) % 60;
      let hours = totalSeconds / 3600;
      hours = this.completionNum(Math.floor(Math.floor(hours * 100) / 100));
      minutes = this.completionNum(Math.floor(Math.floor(minutes * 100) / 100));
      seconds = this.completionNum(Math.floor(Math.floor(seconds * 100) / 100));
      if (hours > 0)
        return hours + ":" + minutes + ":" + seconds;
      else
        return minutes + ":" + seconds;
    } catch (e) {
      logger.error(e);
      return '';
    }
  }

  completionNum(num: any): any {
    if (num < 10)
      return '0' + num;
    else
      return num;
  }

  arrayBufferToBase64(arrayBuffer: ArrayBuffer) {
    const buff = buffer.from(arrayBuffer);
    const base64String = buff.toString('base64');
    return base64String;
  }

  private download(context: common.Context, idx: number, url: string): Promise<memoryImage> {
    return new Promise((resolve) => {
      try {
        let tempDir = context.getApplicationContext().tempDir;
        var rnd = Math.floor((Math.random() * 100) + 1);
        let fileName = `file${Date.now()}${rnd}`;
        let tmpFile = `${tempDir}/${fileName}`;
        request.downloadFile(context, {
          url: url, filePath: tmpFile, enableMetered: true, enableRoaming: true
        }).then((task) => {
          task.on('complete', function callback() {
            fs.open(tmpFile).then((file) => {
              let info = new memoryImage(idx, file.fd, fileName);
              resolve(info);
            });
          });
          task.on('fail', function callBack(err) {
            logger.info('ArkTSCard download task failed. Cause:' + err);
            resolve(null);
          });
        }).catch((res) => {
          logger.error(res);
          resolve(null);
        });
      } catch (e) {
        logger.error(e);
        resolve(null);
      }
    });
  }
}
export default new utils();